package com.suxin.predicate;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author Tang
 * @classname Lazy
 * @description [ 懒加载的工具类 ]
 * @date 2023/3/3 10:49
 */
public class Lazy<T> implements Supplier<T>{

    private final Supplier<T> supplier;

    public Lazy(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    /**
     * of
     * @param supplier
     * @param <T>
     * @return
     */
    public static <T> Lazy<T> of(Supplier<T> supplier) {
        return new Lazy<>(supplier);
    }

    /**
     * map
     * @param function
     * @param <S>
     * @return
     */
    public <S> Lazy<S> map(Function<T, S> function) {
        return Lazy.of(() -> function.apply(this.get()));
    }

    /**
     * flatMap
     * @param lazy
     * @param biFunction
     * @param <S>
     * @param <R>
     * @return
     */
    public <S,R> Lazy<S> flatMap(Lazy<R> lazy, BiFunction<T,R,S> biFunction) {
        return Lazy.of(() -> biFunction.apply(this.get(), lazy.get()));
    }

    /**
     * flatMap
     * lazy1.flatMap((v) -> lazy2.flatMap((v1) -> Lazy.of(() -> getUser(v, v1)))
     * @param function
     * @param <S>
     * @return
     */
    public <S> Lazy<S> flatMap(Function< ? super T, Lazy< ? extends S>> function) {
        return Lazy.of(() -> function.apply(this.get()).get());
    }

    @Override
    public T get() {
        return this.supplier.get();
    }

    public static void main(String[] args) {

        final Lazy<String> lazy1 = Lazy.of(() -> "123");
        final Lazy<String> lazy2 = Lazy.of(() -> "234");
        final Lazy<String> lazy3 = Lazy.of(() -> "456");

        final Lazy<String> stringLazy = lazy3.flatMap((v) -> {
            return Lazy.of(() -> v + "13");
        });

        final Lazy<String> map = lazy1.flatMap((v) -> lazy2.flatMap((v1) -> Lazy.of(() -> getUser(v, v1)))
        );
        System.out.println(map.get());
    }

    private static String getUser(String v, String v1) {
        return v + v1;
    }

}
